package model;

import interfaces.DataBuffer;
import interfaces.ModelInterface;
import interfaces.TagDataGetter;
import interfaces.TagDataChangedListener;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import twitter4j.Twitter;

/**
 * @author Manseer Marcel  
 * @author Plavsic Maja
 * @author Pretsch Paul
 */
public class Model implements ModelInterface{

	private DataBuffer buffer;
	private final Twitter twitter;
	private ExecutorService executor;
	private List<Future<?>> futures;
	
	public Model()
	{
		this.buffer = new MemoryDataBuffer();
		this.twitter = Authenticator.authenticateStatic(Long.MIN_VALUE);
		this.futures = new ArrayList<Future<?>>();
	}
	
	private ExecutorService getExecutor()
	{
		if (this.executor == null) {
			this.executor = Executors.newScheduledThreadPool(3);
		}	
		return this.executor;
	}

	/* (non-Javadoc)
	 * @see interfaces.ModelInterface#requestTweetCountForTagSince(java.util.Date, java.lang.String[])
	 */
	@Override
	public void requestTweetCountForTagSince(Date since, String... hashtags) {
		since = Tools.TruncateTime(since);
		Date date = Tools.TruncateTime(new Date());
		
		List<TagDataGetter> existingData = buffer.getTwitterData(since, date, hashtags);
		for (TagDataGetter tagData: existingData) {
			if (tagData.getFinished()) {
				tagData.fireTagDataChanged(0);
			} else {
				buffer.removeData(tagData.getDate(), tagData.getTag());
			}
		}
		
		do {
//			request Data for single day
			for (String hashtag : hashtags) {
				requestTweetCountForTag(hashtag, date);
			}
//			get prev day
			date = Tools.IncDay(date, -1);
		} while (since.before(date));
	}
	
	private void requestTweetCountForTag(String hashtag, Date date) {
		if (twitter != null) {
			TagDataCrawler worker = new TagDataCrawler(this, hashtag, date);
			futures.add(getExecutor().submit(worker));			
		}
	}

	/* (non-Javadoc)
	 * @see interfaces.ModelInterface#cancelAllQueries()
	 */
	@Override
	public void cancelAllQueries() {
		System.out.println("Model: cancelAllQueries called");
		if (this.executor != null) {
			this.executor.shutdownNow();
			for (Future<?> future : futures) {
				if (!future.isDone()) {
					future.cancel(true);
				}
			}
			
			try {
				this.executor.awaitTermination(5000, TimeUnit.MILLISECONDS);
			} catch (InterruptedException e) {
				System.out.println("Model: awaitTermination failed");
			}
			this.executor = null;
		}
	}

	public DataBuffer getBuffer() {
		return this.buffer;
	}

	public Twitter getTwitter() {
		return this.twitter;
	}
	
	/**
	 * adds a new data chaged listener to the model
	 * event is fired whenever data for a tag has changed
	 * 
	 * @param listener
	 */
	public void addTagDataChangedListener(TagDataChangedListener listener) {
		buffer.addTagDataChangedListener(listener);
	}

}
	
